﻿package igz.fleaxy.ui.table 
{
	import com.greensock.TweenNano;
	import flash.display.Bitmap;
	import flash.display.DisplayObject;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.text.TextFormatAlign;
	import flash.ui.MouseCursor;
	import igz.fleaxy.Fleaxy;
	import igz.fleaxy.io.MouseManager;
	import igz.fleaxy.ui.scrollbar.ScrollBarH;
	import igz.fleaxy.ui.text.LabelUi;
	import igz.fleaxy.ui.scrollbar.ScrollBarContainerUi;
	import igz.fleaxy.ui.scrollbar.ScrollBarV;
	import igz.fleaxy.ui.scrollbar.ScrollContainerUi;
	import igz.fleaxy.util.DataTableUtil;
	import igz.fleaxy.util.ObjectUtil;
	import igz.fleaxy.util.SpriteUtil;
	
	/**
	 * @author Intelygenz | www.intelygenz.com
	 */
	public class TableUi extends Sprite {

		[Embed( source = "../../../../../image/mouse_cursor/mouse_cursor_resize.png", mimeType="image/png") ]
		static private var _MouseCursorResizeClass:Class;
		static protected function get _MouseCursorResize() : Bitmap {
			return new _MouseCursorResizeClass() as Bitmap;
		}

		protected var _MainContainer : ScrollContainerUi;
		protected var _MainContainerScrollH : ScrollBarH;

		protected var _DataTable:Object;
		public function get $DataTable() : Object {
			return _DataTable;
		}

		protected var _HeaderColumns:Array;
		public function get $HeaderColumns() : Array {
			return _HeaderColumns;
		}

		protected var _HeaderUi : TableRowUi;
		public function get $HeaderUi() : TableRowUi {
			return _HeaderUi;
		}

		protected var _DataColumns:Array;
		public function get $DataColumns() : Array {
			return _DataColumns;
		}
		protected var _DataRowEvents:Object;

		protected var _DataUi:ScrollContainerUi;
		public function get $DataUi():ScrollContainerUi { return _DataUi; }
		
		internal var _DataUiScrollBarV:ScrollBarV;
		protected var _DataRowsUi : Array;
		

		protected var _FooterColumns:Array;
		public function get $FooterColumns() : Array {
			return _FooterColumns;
		}
		protected var _FooterUi:TableRowUi;

		protected var _Settings:Object;
		public function get $Settings() : Object {
			return _Settings;
		}
		
		protected var _ResizeLineSelected : Sprite;
		protected var _ColumnSelectedIndex : uint;
		protected var _ResizeLinesUi : Array;
		
		protected var _SortGraphics : Shape;
		protected var _LastSortedField : TableFieldUi;
		protected var _SortAscending : Boolean;

		protected var _Messages:Object;


		/**
		 * Tabla básica para pintar listados con posibilidad de barra de scroll en las filas
		 * 
		 * @param	p_settings { "styleHeader"       : "tableHeader" 
						, "styleRow0"         : "tableRow0" 
						, "styleRow1"         : "tableRow1" 
						, "styleFooter"       : "tableFooter" 
						, "styleScrollBarBg"   : "tableScrollBarBg" 
						, "styleScrollBarMark" : "tableScrollBarMark" 
						, "styleTopCss"	      : "tableTop"
						, "styleBottomCss"    : "tableBottom"
						, "styleNoResultsCss" : "tableNoResults"
						, "scrollHeight"      : 100
						, "width" 	   	      : 0
						, "fieldMaxLines"     : 1
						, "alignCenter" : false
						}

		* @param	p_messages { "msgTop"       : ""
						, "msgBottom"    : "Se devolvieron <B><ROWS /></B> resultados"
						, "msgNoResults" : "No hay ningún resultado"
					    }
		*/
		public function TableUi(p_settings:Object = null, p_messages:Object = null) {
			_Settings = { "styleHeader"           : "tableHeader" 
						, "styleRow0"             : "tableRow0" 
						, "styleRow1"             : "tableRow1" 
						, "styleFooter"           : "tableFooter" 
						, "styleScrollBarBg"      : "tableScrollBarBg" 
						, "styleScrollBarMark"    : "tableScrollBarMark" 
						, "styleTopCss"	          : "tableTop"
						, "styleBottomCss"        : "tableBottom"
						, "styleNoResultsCss"     : "tableNoResults"
						, "scrollBackground"  	  : 0xFFFFFF
						, "scrollBackgroundAlpha" : 1
						, "width" 	   	          : 0
						, "fieldMaxLines"         : 1
						, "tableWidth"			  : 100
						, "tableHeight"			  : 100
						//, "autoHeight" : false // TODO: Test it!
						, "showScrollBarV"		  : true
						, "showScrollBarH"		  : true
						, "resizableColumns"	  : false
						, "onColumnResize"		  : null // function ( p_headerColumn:Object )
						, "onColumnSort"		  : null // function ( p_fieldUi:TableFieldUi )
						, "fieldMinWidth"		  : 20 // Tamaño mínimo para una celda`
						}
						
			_Messages = { "msgTop"       : ""
						, "msgBottom"    : "Se devolvieron <B><ROWS /></B> resultados"
						, "msgNoResults" : "No hay ningún resultado"
					    }

			ObjectUtil.$Merge(p_settings, _Settings);

			ObjectUtil.$Merge(p_messages, _Messages);
			_MainContainer = new ScrollContainerUi({  "background": _Settings["scrollBackground"]
													, "backgroundAlpha": _Settings["scrollBackgroundAlpha"]
													});
			addChild( _MainContainer );
			
			if ( _Settings["showScrollBarH"] ) {
				_MainContainerScrollH = new ScrollBarH( _MainContainer, { backgroundStyle : _Settings["styleScrollBarBg"], markStyle : _Settings["styleScrollBarMark"] } );
			
				addChild( _MainContainerScrollH );
			}
			
			_HeaderUi = new TableRowUi(this, { }, { "styleName" : _Settings["styleHeader"], "headerRow" : true } );
			_HeaderUi = new TableRowUi(this, { }, { "styleName" : _Settings["styleHeader"], "headerRow" : true } );
			_MainContainer.addChild( _HeaderUi );

			_DataUi = new ScrollContainerUi( { "height": _Settings["scrollHeight"]
											 , "background": _Settings["scrollBackground"]
											 , "backgroundAlpha": _Settings["scrollBackgroundAlpha"]
											});
			_MainContainer.addChild( _DataUi );

			if ( _Settings["showScrollBarV"] ) {
				_DataUiScrollBarV = new ScrollBarV( _DataUi
												, { "backgroundStyle" : _Settings["styleScrollBarBg"], "markStyle" : _Settings["styleScrollBarMark"] }
												, { "autoPos" : false }
												);
				addChild( _DataUiScrollBarV );
			}
			
			_SortGraphics = new Shape();
			_MainContainer.addChild( _SortGraphics );
		}

		/**
		 * Define la cabecera, se le pasa un array con los elementos de la cabecera
		 * 
		 * @param	p_headerColumns Array con los elementos de la cabecera
		 * 
		 * @example
		 * 
		 * $DefineHeader([ {  "inner":"Ejemplo"
		 * 					, "order":"Ejemplo@Tabla"
		 * 					, "width":200
		 * 					, "visible":true
		 * 					, "textAlign" : TextFormatAlign.LEFT
		 * 					} ]);
		 */
		public function $DefineHeader(p_headerColumns:Array) : void {
			
			_HeaderColumns = new Array();
			
			var defaultSettings : Object;
			var headerSetting : Object;
			for each ( headerSetting in p_headerColumns ) {
				defaultSettings = {
					 "visible" : true
					,"textAlign" : TextFormatAlign.LEFT
					, "width" : 200
				};
				ObjectUtil.$Merge( headerSetting, defaultSettings );
				_HeaderColumns.push( defaultSettings );
			}
		}

		/**
		 * Define el contenido de los registros de la tabla
		 * 
		 * @param	p_dataColumns 
		 * @param	p_rowEvents
		 * @example
		 * 
		 * $DefineData([ { "inner" : "<DT>Apellidos@Usuario</DT>, <DT>Nombre@Usuario</DT>" } ]);
		 */
		public function $DefineData(p_dataColumns:Array, p_rowEvents:Object) : void {
			_DataColumns   = p_dataColumns;
			_DataRowEvents = p_rowEvents;
		}

		public function $DefineFooter(p_footerColumns:Array) : void {
			_FooterColumns = p_footerColumns;
			
			if ( _FooterColumns.length > 0 && _FooterUi == null ) {
				_FooterUi = new TableRowUi(this, { }, { "styleName" : _Settings["styleFooter"] } );
				_MainContainer.addChild( _FooterUi );
			}
		}

		/**
		 * Rellena la tabla a partir de un datatable, se tiene en cuenta que ya se han rellenado los _headerColums, 
		 * 
		 * example: dataTable : Object = { DataTableUtil.$COLUMNS_LABEL:["nomColumn",...], DataTableUtil.$ROWS_LABEL:[ ["valueColumn",...] ... ] };
		 * 
		 * @param	p_dataTable Datatable con los datos a rellenar
		 */
		public function $LoadFromDataTable ( p_dataTable:Object ) : void {
			_DataTable = p_dataTable;
			
			var dataLength : uint = DataTableUtil.$Length(_DataTable);
			var f : uint;
			
			// Load Header Row
			if ( _HeaderColumns != null && _HeaderColumns.length > 0 ) {
				_HeaderUi.$Load( _HeaderColumns );
				if ( _Settings["resizableColumns"] ) {
					_CreateResizeLines();
				}
			}

			// Create Data Rows
			_DataUi.$Clear();
			_DataRowsUi = new Array();
			
			var rowUi:TableRowUi;
			for ( f = 0; f < dataLength; f++ ) {
				rowUi = new TableRowUi(this, _DataRowEvents, { "showScrollBarH" : _Settings["showScrollBarH"], "alignCenter" : _Settings["alignCenter"], "styleName" : _Settings[ "styleRow" + (f & 1)] } );
				rowUi.$Load( _DataColumns, DataTableUtil.$GetRow(_DataTable, f) );
				_DataUi.addChild(rowUi);
				_DataRowsUi.push( rowUi );
			}
			
			// Load Footer 
			if ( _FooterColumns != null && _FooterColumns.length > 0 ) {
				_FooterUi.$Load(_FooterColumns);
			}
		}

		public function $Draw() : void {
			_HeaderUi.$Draw();
			
			if ( _Settings["resizableColumns"] ) {
				var resizeLine : Sprite;
				var columnIndex : uint;
				var fieldUi : TableFieldUi;
				for ( columnIndex = 0; columnIndex < _HeaderColumns.length; columnIndex++ ) {
					resizeLine = _ResizeLinesUi[ columnIndex ];

					if ( _HeaderColumns[columnIndex]["visible"] ) {
						if ( !resizeLine.parent ) {
							_MainContainer.addChild( resizeLine );
						}
					}
					else if ( resizeLine.parent ) {
						_MainContainer.removeChild( resizeLine );
					}
					fieldUi = _HeaderUi.$TableFieldUi[columnIndex];
					resizeLine.x = fieldUi.x + fieldUi.width-1;
				}
			}
			
			
			var rowUi:TableRowUi;
			var nextY:uint = 0;
			for each ( rowUi in _DataRowsUi ) {
				rowUi.$Draw();
				rowUi.y = nextY;
				nextY += rowUi.height;
			}
/*
			if (_Settings["autoHeight"]) {
				_Settings["tableHeight"] = _DataUi.$Container.height + _HeaderUi.height + (_MainContainerScrollH != null ? _MainContainerScrollH.height: 0);
			}
*/
			if ( _Settings["showScrollBarH"] ) {
				_MainContainer.height = _Settings["tableHeight"] - _MainContainerScrollH.height;
			}
			else {
				_MainContainer.height = _Settings["tableHeight"];
			}

			_MainContainer.width  = _Settings["tableWidth"] - _DataUiScrollBarV.width;
			_DataUi.width  = _DataUi.$Container.width;
			if ( _Settings["showScrollBarV"] ) {
				_DataUi.height = _MainContainer.height - _HeaderUi.height;
			}
			else {
				_DataUi.height = _DataUi.$Container.height;
			}
			_DataUi.y = _HeaderUi.height;

			_DataUiScrollBarV.x = _Settings["tableWidth"] - _DataUiScrollBarV.width;
			_DataUiScrollBarV.y = _DataUi.y;

			_DrawResizeLines();

			if ( _FooterUi != null ) {
				_FooterUi.$Draw();
				_FooterUi.y = _DataUi.y + _DataUi.height;
			}
			
			_DrawSortGraphics();

			//_MainContainer.$RefreshScrollBars(); No le da tiempo a refrescar correctamente
			TweenNano.delayedCall(0.4, _RefreshScrollBars);
		}
		
		private function _RefreshScrollBars():void {
			_MainContainer.$RefreshScrollBars();
			_DataUi.$RefreshScrollBars();
		}
		
		public function $RefreshStyles() : void {
			_HeaderUi.$ApplyStyle( _Settings["styleHeader"] );
			
			var rowUi : TableRowUi;
			var f:uint; var F:uint = _DataRowsUi.length;
			for ( f = 0; f < F; f++ ) {
				rowUi = _DataRowsUi[f] as TableRowUi;
				rowUi.$ApplyStyle( _Settings["styleRow" + (f & 1)] );
			}
			
			if ( _FooterUi != null ) {
				_FooterUi.$ApplyStyle( _Settings["styleFooter"] );
			}
			if ( _Settings["showScrollBarH"] ) {
				_MainContainerScrollH.$SetStyles( { "backgroundStyle" : _Settings["styleScrollBarBg"], "markStyle" : _Settings["styleScrollBarMark"] } );
			}
			_DataUiScrollBarV.$SetStyles( { "backgroundStyle" : _Settings["styleScrollBarBg"], "markStyle" : _Settings["styleScrollBarMark"] } );
		}

		override public function set height (p_height:Number) : void {
			_Settings["tableHeight"] = p_height;
		}
		override public function get height () : Number {
			return _Settings["tableHeight"];
		}

		override public function set width (p_width:Number) : void {
			_Settings["tableWidth"] = p_width;
		}

		override public function get width () : Number {
			return _Settings["tableWidth"];
		}

		//
		// Columns resize
		//
		private function _CreateResizeLines () : void {
			var resizeLine : Sprite;
			
			_ResizeLinesUi = new Array();
			
			var columnIndex : uint;
			var resizeLineUi : Sprite;
			for ( columnIndex = 0; columnIndex < _HeaderColumns.length; columnIndex++ ) {
				_CreateResizeLine();
			}
			_DrawResizeLines();
		}

		private function _CreateResizeLine () : void {
			var resizeLine : Sprite = new Sprite();
			resizeLine.alpha = 0.5;
			_ResizeLinesUi.push( resizeLine );
			
			resizeLine.addEventListener(MouseEvent.MOUSE_DOWN, _ResizeLine_OnMouseDown);
			resizeLine.addEventListener(MouseEvent.MOUSE_OVER, _ResizeLine_OnMouseOver);
			resizeLine.addEventListener(MouseEvent.MOUSE_OUT, _ResizeLine_OnMouseOut);
		}
		
		private function _DrawResizeLines():void {
			var resizeLine : Sprite;
			var resizeHeight : uint = _DataUi.$Container.height + _HeaderUi.height;
			for each ( resizeLine in _ResizeLinesUi ) {
				resizeLine.graphics.clear();
				resizeLine.graphics.beginFill( 0, 0 );
				resizeLine.graphics.drawRect(-2, 0, 5, resizeHeight);
				resizeLine.graphics.endFill();
				resizeLine.graphics.lineStyle(1, 0);
				resizeLine.graphics.moveTo(0, 0);
				resizeLine.graphics.lineTo(0, resizeHeight);
			}
		}
		
		private function _ResizeLine_OnMouseOut ( p_mouseEvent:MouseEvent ) : void {
			_ResetCursor();
		}
		
		private function _ResetCursor():void {
			MouseManager.$ShowCursor( MouseCursor.AUTO );
		}
		
		private function _ResizeLine_OnMouseOver ( p_mouseEvent:MouseEvent ) : void {
			MouseManager.$Show( _MouseCursorResize, new Point(-_MouseCursorResize.width/2,-_MouseCursorResize.height/2) );
		}
		
		private function _ResizeLine_OnMouseDown ( p_mouseEvent:MouseEvent ) : void {
			p_mouseEvent.stopPropagation();
			
			_ResizeLineSelected = p_mouseEvent.target as Sprite;
			_ColumnSelectedIndex = _ResizeLinesUi.indexOf( _ResizeLineSelected );
			_ResizeLineSelected.alpha = 1;
			_ResizeLineSelected.removeEventListener( MouseEvent.MOUSE_OUT, _ResizeLine_OnMouseOut );

			Fleaxy.$Current.$Stage.addEventListener( MouseEvent.MOUSE_MOVE, _Stage_OnMouseMove );
			Fleaxy.$Current.$Stage.addEventListener( MouseEvent.MOUSE_UP, _Stage_OnMouseUp );
		}
		
		private function _Stage_OnMouseMove ( p_mouseEvent:MouseEvent ) : void {
			p_mouseEvent.stopPropagation();

			var newX : Number = this.mouseX - _MainContainer.$Container.x;
			var minX : Number =  (_ColumnSelectedIndex == 0) ? _Settings["fieldMinWidth"] : _HeaderUi.$TableFieldUi[_ColumnSelectedIndex].x + _Settings["fieldMinWidth"];
			if ( newX < minX ) {
				newX = minX;
			}

			_ResizeLineSelected.x = newX;
		}
		
		private function _Stage_OnMouseUp ( p_mouseEvent:MouseEvent ) : void {
			Fleaxy.$Current.$Stage.removeEventListener( MouseEvent.MOUSE_MOVE, _Stage_OnMouseMove );
			Fleaxy.$Current.$Stage.removeEventListener( MouseEvent.MOUSE_UP, _Stage_OnMouseUp );
			
			_ResizeLineSelected.alpha = 0.5;
			_ResizeLineSelected.addEventListener(MouseEvent.MOUSE_OUT, _ResizeLine_OnMouseOut);
			_ResetCursor();

			var newWidth : int = this.mouseX - _MainContainer.$Container.x - _HeaderUi.$TableFieldUi[_ColumnSelectedIndex].x;
			if ( newWidth < 0 ) {
				newWidth = _Settings["fieldMinWidth"];
			}
			else if ( newWidth < _Settings["fieldMinWidth"] ) {
				newWidth = _Settings["fieldMinWidth"];
			}

			_HeaderColumns[_ColumnSelectedIndex]["width"] = newWidth;

			$Draw();

			if ( _Settings["onColumnResize"] is Function ) {
				_Settings["onColumnResize"]( _HeaderColumns[_ColumnSelectedIndex] );
			}
		}
		
		
		//
		// Column sort
		//
		public function $SortAt ( p_headerFieldIndex:uint ) : void {
			$Sort( _HeaderUi.$TableFieldUi[p_headerFieldIndex] );
		}

		public function $Sort ( p_headerField:TableFieldUi ) : void {
			var columnSorted : Array = DataTableUtil.$SortColumn( _DataTable
																, p_headerField.$Settings["sortField"]
																, { "returnIndex":true, "descending":!_SortAscending } 
																);

			var f:uint; var F:uint = _HeaderColumns.length;
			var g:uint; var G:uint = columnSorted.length;
			var column : Array;
			for ( f = 0; f < F; f++ ) {
				column = DataTableUtil.$GetColumnAt( _DataTable, f );
				for (g = 0; g < G; g++) {
					((_DataRowsUi[g] as TableRowUi).$TableFieldUi[f] as TableFieldUi).$SetInner( column[columnSorted[g]] );
				}
			}

			_LastSortedField = p_headerField;
			_DrawSortGraphics();

			_SortAscending = !_SortAscending;
		}
		
		private function _DrawSortGraphics () : void {
			_SortGraphics.graphics.clear();
			
			if ( _LastSortedField != null &&  _LastSortedField.visible ) {
				_SortGraphics.graphics.beginFill( 0, 0.1 );
				_SortGraphics.graphics.drawRect(_LastSortedField.x, _LastSortedField.y, _LastSortedField.width, _DataUi.$Container.height+_HeaderUi.height);
				_SortGraphics.graphics.endFill();
				
				_SortGraphics.graphics.beginFill(0xffffff, 0.7);
				const _SORT_ARROW_SIZE : uint = 5;
				var lastShortedFieldX : Number = _LastSortedField.x + _LastSortedField.width / 2;
				
				if ( _SortAscending ) {
					_SortGraphics.graphics.moveTo(lastShortedFieldX, _LastSortedField.y+1);
					_SortGraphics.graphics.lineTo(lastShortedFieldX - _SORT_ARROW_SIZE, _LastSortedField.y+_SORT_ARROW_SIZE);
					_SortGraphics.graphics.lineTo(lastShortedFieldX + _SORT_ARROW_SIZE, _LastSortedField.y+_SORT_ARROW_SIZE);
					_SortGraphics.graphics.lineTo(lastShortedFieldX, _LastSortedField.y+1);
					_SortGraphics.graphics.endFill();
				}
				else {
					_SortGraphics.graphics.moveTo(lastShortedFieldX, _LastSortedField.y+_SORT_ARROW_SIZE);
					_SortGraphics.graphics.lineTo(lastShortedFieldX - _SORT_ARROW_SIZE, _LastSortedField.y+1);
					_SortGraphics.graphics.lineTo(lastShortedFieldX + _SORT_ARROW_SIZE, _LastSortedField.y+1);
					_SortGraphics.graphics.lineTo(lastShortedFieldX, _LastSortedField.y+_SORT_ARROW_SIZE);
					_SortGraphics.graphics.endFill();
				}
			}
		}
	}
	
}